home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / strategy / xpuzzles.3 / xpuzzles / xpuzzles-5.3.1 / xcubes / Cubes.c < prev    next >
C/C++ Source or Header  |  1996-04-08  |  33KB  |  1,134 lines

  1. /*
  2. # X-BASED CUBES
  3. #
  4. #  Cubes.c
  5. #
  6. ###
  7. #
  8. #  Copyright (c) 1994 - 96    David Albert Bagley, bagleyd@hertz.njit.edu
  9. #
  10. #                   All Rights Reserved
  11. #
  12. #  Permission to use, copy, modify, and distribute this software and
  13. #  its documentation for any purpose and without fee is hereby granted,
  14. #  provided that the above copyright notice appear in all copies and
  15. #  that both that copyright notice and this permission notice appear in
  16. #  supporting documentation, and that the name of the author not be
  17. #  used in advertising or publicity pertaining to distribution of the
  18. #  software without specific, written prior permission.
  19. #
  20. #  This program is distributed in the hope that it will be "playable",
  21. #  but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  23. #
  24. */
  25.  
  26. /* Methods file for Cubes */
  27.  
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #ifdef VMS
  31. #include <unixlib.h>
  32. #else
  33. #ifndef apollo
  34. #include <unistd.h>
  35. #endif
  36. #endif
  37. #include <X11/IntrinsicP.h>
  38. #include <X11/Intrinsic.h>
  39. #include <X11/StringDefs.h>
  40. #include <X11/CoreP.h>
  41. #include "CubesP.h"
  42.  
  43. #ifndef DATAFILE
  44. #define DATAFILE "/usr/games/lib/cubes.data"
  45. #endif
  46.  
  47. static void InitializeCubes();
  48. static void ExposeCubes();
  49. static void ResizeCubes();
  50. static void DestroyCubes();
  51. static Boolean SetValuesCubes();
  52.  
  53. static void QuitCubes();
  54. static void MoveCubesOut();
  55. static void MoveCubesTop();
  56. static void MoveCubesLeft();
  57. static void MoveCubesIn();
  58. static void MoveCubesRight();
  59. static void MoveCubesBottom();
  60. static void SelectCubes();
  61. static void ReleaseCubes();
  62. static void RandomizeCubes();
  63. static void RandomizeCubesMaybe();
  64. static void GetCubes();
  65. static void WriteCubes();
  66. static void UndoCubes();
  67. static void SolveCubes();
  68. static int MoveCubes();
  69. static int PositionToBrick();
  70. static void SelectBricks();
  71. static void CheckBricks();
  72. static void ResetBricks();
  73. static void ResizeBricks();
  74. static void MoveNoBricks();
  75. static int MoveBricksDir();
  76. static void RandomizeBricks();
  77. static void MoveBricks();
  78. static int ExchangeBricks();
  79. static void DrawFrame();
  80. static void DrawBrick();
  81. static int Row();
  82. static int Column();
  83. static int Stack();
  84.  
  85. static char defaultTranslationsCubes[] =
  86.   "<KeyPress>q: Quit()\n\
  87.    Ctrl<KeyPress>C: Quit()\n\
  88.    <KeyPress>o: MoveOut()\n\
  89.    <KeyPress>KP_Divide: MoveOut()\n\
  90.    <KeyPress>R5: MoveOut()\n\
  91.    <KeyPress>Up: MoveTop()\n\
  92.    <KeyPress>KP_8: MoveTop()\n\
  93.    <KeyPress>R8: MoveTop()\n\
  94.    <KeyPress>Left: MoveLeft()\n\
  95.    <KeyPress>KP_4: MoveLeft()\n\
  96.    <KeyPress>R10: MoveLeft()\n\
  97.    <KeyPress>i: MoveIn()\n\
  98.    <KeyPress>Begin: MoveIn()\n\
  99.    <KeyPress>KP_5: MoveIn()\n\
  100.    <KeyPress>R11: MoveIn()\n\
  101.    <KeyPress>Right: MoveRight()\n\
  102.    <KeyPress>KP_6: MoveRight()\n\
  103.    <KeyPress>R12: MoveRight()\n\
  104.    <KeyPress>Down: MoveBottom()\n\
  105.    <KeyPress>KP_2: MoveBottom()\n\
  106.    <KeyPress>R14: MoveBottom()\n\
  107.    <Btn1Down>: Select()\n\
  108.    <Btn1Up>: Release()\n\
  109.    <KeyPress>r: Randomize()\n\
  110.    <Btn3Down>(2+): Randomize()\n\
  111.    <Btn3Down>: RandomizeMaybe()\n\
  112.    <KeyPress>g: Get()\n\
  113.    <KeyPress>w: Write()\n\
  114.    <KeyPress>u: Undo()\n\
  115.    <KeyPress>s: Solve()";
  116.  
  117. static XtActionsRec actionsListCubes[] =
  118. {
  119.   {"Quit", (XtActionProc) QuitCubes},
  120.   {"MoveOut", (XtActionProc) MoveCubesOut},
  121.   {"MoveTop", (XtActionProc) MoveCubesTop},
  122.   {"MoveLeft", (XtActionProc) MoveCubesLeft},
  123.   {"MoveIn", (XtActionProc) MoveCubesIn},
  124.   {"MoveRight", (XtActionProc) MoveCubesRight},
  125.   {"MoveBottom", (XtActionProc) MoveCubesBottom},
  126.   {"Select", (XtActionProc) SelectCubes},
  127.   {"Release", (XtActionProc) ReleaseCubes},
  128.   {"Randomize", (XtActionProc) RandomizeCubes},
  129.   {"RandomizeMaybe", (XtActionProc) RandomizeCubesMaybe},
  130.   {"Get", (XtActionProc) GetCubes},
  131.   {"Write", (XtActionProc) WriteCubes},
  132.   {"Undo", (XtActionProc) UndoCubes},
  133.   {"Solve", (XtActionProc) SolveCubes}
  134. };
  135.  
  136. static XtResource resourcesCubes[] =
  137. {
  138.   {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
  139.    XtOffset(CubesWidget, cubes.foreground), XtRString, XtDefaultForeground},
  140.   {XtNbrickColor, XtCColor, XtRPixel, sizeof(Pixel),
  141.    XtOffset(CubesWidget, cubes.brickColor), XtRString, XtDefaultForeground},
  142.   {XtNbrickBorder, XtCColor, XtRPixel, sizeof(Pixel),
  143.    XtOffset(CubesWidget, cubes.borderColor), XtRString, XtDefaultForeground},
  144.   {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
  145.    XtOffset(CubesWidget, core.width), XtRString, "100"},
  146.   {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
  147.    XtOffset(CubesWidget, core.height), XtRString, "300"},
  148.   {XtNsizeX, XtCSizeX, XtRInt, sizeof(int),
  149.    XtOffset(CubesWidget, cubes.sizeX), XtRString, "3"}, /* DEFAULTCUBES */
  150.   {XtNsizeY, XtCSizeY, XtRInt, sizeof(int),
  151.    XtOffset(CubesWidget, cubes.sizeY), XtRString, "3"}, /* DEFAULTCUBES */
  152.   {XtNsizeZ, XtCSizeZ, XtRInt, sizeof(int),
  153.    XtOffset(CubesWidget, cubes.sizeZ), XtRString, "3"}, /* DEFAULTCUBES */
  154.   {XtNbase, XtCBase, XtRInt, sizeof(int),
  155.    XtOffset(CubesWidget, cubes.base), XtRString, "10"},
  156.   {XtNstart, XtCBoolean, XtRBoolean, sizeof(Boolean),
  157.    XtOffset(CubesWidget, cubes.started), XtRString, "FALSE"},
  158.   {XtNselectCallback, XtCCallback, XtRCallback, sizeof(caddr_t),
  159.    XtOffset(CubesWidget, cubes.select), XtRCallback, NULL}
  160. };
  161.  
  162. CubesClassRec cubesClassRec =
  163. {
  164.   {
  165.     (WidgetClass) &widgetClassRec,    /* superclass */
  166.     "Cubes",                /* class name */
  167.     sizeof(CubesRec),            /* widget size */
  168.     NULL,                /* class initialize */
  169.     NULL,                /* class part initialize */
  170.     FALSE,                /* class inited */
  171.     InitializeCubes,            /* initialize */
  172.     NULL,                /* initialize hook */
  173.     XtInheritRealize,            /* realize */
  174.     actionsListCubes,            /* actions */
  175.     XtNumber(actionsListCubes),        /* num actions */
  176.     resourcesCubes,            /* resources */
  177.     XtNumber(resourcesCubes),        /* num resources */
  178.     NULLQUARK,                /* xrm class */
  179.     TRUE,                /* compress motion */
  180.     TRUE,                /* compress exposure */
  181.     TRUE,                /* compress enterleave */
  182.     TRUE,                /* visible interest */
  183.     DestroyCubes,            /* destroy */
  184.     ResizeCubes,            /* resize */
  185.     ExposeCubes,            /* expose */
  186.     SetValuesCubes,            /* set values */
  187.     NULL,                /* set values hook */
  188.     XtInheritSetValuesAlmost,        /* set values almost */
  189.     NULL,                /* get values hook */
  190.     NULL,                /* accept focus */
  191.     XtVersion,                /* version */
  192.     NULL,                /* callback private */
  193.     defaultTranslationsCubes,        /* tm table */
  194.     NULL,                /* query geometry */
  195.     NULL,                /* display accelerator */
  196.     NULL                /* extension */
  197.   },
  198.   {
  199.     0                    /* ignore */
  200.   }
  201. };
  202.  
  203. WidgetClass cubesWidgetClass = (WidgetClass) &cubesClassRec;
  204.  
  205. static void InitializeCubes(request, new)
  206.   Widget request, new;
  207. {
  208.   CubesWidget w = (CubesWidget) new;
  209.   XGCValues values;
  210.   XtGCMask valueMask;
  211.  
  212.   w->cubes.brickOfPosition = NULL;
  213.   CheckBricks(w);
  214.   InitMoves();
  215.   ResetBricks(w);
  216.   (void) SRAND(getpid());
  217.   valueMask = GCForeground | GCBackground;
  218.   values.foreground = w->cubes.foreground;
  219.   values.background = w->core.background_pixel;
  220.   w->cubes.puzzleGC = XtGetGC(new, valueMask, &values);
  221.   values.foreground = w->cubes.brickColor;
  222.   w->cubes.brickGC = XtGetGC(new, valueMask, &values);
  223.   values.foreground = w->cubes.borderColor;
  224.   w->cubes.borderGC = XtGetGC(new, valueMask, &values);
  225.   valueMask = GCForeground | GCBackground;
  226.   values.foreground = w->core.background_pixel;
  227.   values.background = w->cubes.foreground;
  228.   w->cubes.inverseGC = XtGetGC(new, valueMask, &values);
  229.   ResizeCubes(w);
  230. }
  231.  
  232. static void DestroyCubes(old)
  233.   Widget old;
  234. {
  235.   CubesWidget w = (CubesWidget) old;
  236.  
  237.   XtReleaseGC(old, w->cubes.brickGC);
  238.   XtReleaseGC(old, w->cubes.borderGC);
  239.   XtReleaseGC(old, w->cubes.puzzleGC);
  240.   XtReleaseGC(old, w->cubes.inverseGC);
  241.   XtRemoveCallbacks(old, XtNselectCallback, w->cubes.select);
  242. }
  243.  
  244. static void ResizeCubes(w)
  245.   CubesWidget w;
  246. {
  247.   w->cubes.delta.x = 3;
  248.   w->cubes.delta.y = 3;
  249.   w->cubes.offset.x = MAX(((int) w->core.width - w->cubes.delta.x) /
  250.     w->cubes.sizeX, 0);
  251.   w->cubes.offset.y = MAX(((int) w->core.height - w->cubes.delta.y) /
  252.     w->cubes.sizeY, 0);
  253.   if (w->cubes.offset.y >= w->cubes.offset.x) {
  254.     w->cubes.vertical = TRUE;
  255.     w->cubes.offset.y = MAX(((int) w->core.height / w->cubes.sizeZ -
  256.       w->cubes.delta.y) / w->cubes.sizeY, 0);
  257.   } else {
  258.     w->cubes.vertical = FALSE;
  259.     w->cubes.offset.x = MAX(((int) w->core.width / w->cubes.sizeZ -
  260.       w->cubes.delta.x) / w->cubes.sizeX, 0);
  261.   }
  262.   w->cubes.faceSize.x = w->cubes.offset.x * w->cubes.sizeX +
  263.     w->cubes.delta.x + 2;
  264.   w->cubes.faceSize.y = w->cubes.offset.y * w->cubes.sizeY +
  265.     w->cubes.delta.y + 2;
  266.   if (w->cubes.vertical) {
  267.     w->cubes.puzzleSize.x = w->cubes.faceSize.x;
  268.     w->cubes.puzzleSize.y = (w->cubes.faceSize.y - w->cubes.delta.y) *
  269.       w->cubes.sizeZ + w->cubes.delta.y;
  270.   } else {
  271.     w->cubes.puzzleSize.x = (w->cubes.faceSize.x - w->cubes.delta.x) *
  272.       w->cubes.sizeZ + w->cubes.delta.x;
  273.     w->cubes.puzzleSize.y = w->cubes.faceSize.y;
  274.   }
  275.   w->cubes.puzzleOffset.x = ((int) w->core.width -
  276.     w->cubes.puzzleSize.x + 2) / 2;
  277.   w->cubes.puzzleOffset.y = ((int) w->core.height -
  278.     w->cubes.puzzleSize.y + 2) / 2;
  279.   w->cubes.brickSize.x = MAX(w->cubes.offset.x - w->cubes.delta.x, 0);
  280.   w->cubes.brickSize.y = MAX(w->cubes.offset.y - w->cubes.delta.y , 0);
  281.   ResizeBricks(w);
  282. }
  283.  
  284. static void ExposeCubes(new, event, region)
  285.   Widget new;
  286.   XEvent *event;
  287.   Region region; /* Not used */
  288. {
  289.   CubesWidget w = (CubesWidget) new;
  290.  
  291.   if (w->core.visible) {
  292.     DrawFrame(w, w->cubes.puzzleGC);
  293.     DrawAllBricks(w, w->cubes.brickGC, w->cubes.borderGC);
  294.   }
  295. }
  296.  
  297. static Boolean SetValuesCubes(current, request, new)
  298.   Widget current, request, new;
  299. {
  300.   CubesWidget c = (CubesWidget) current, w = (CubesWidget) new;
  301.   XGCValues values;
  302.   XtGCMask valueMask;
  303.   Boolean redraw = FALSE;
  304.   Boolean redrawBricks = FALSE;
  305.  
  306.   CheckBricks(w);
  307.   if (w->cubes.foreground != c->cubes.foreground) {
  308.     valueMask = GCForeground | GCBackground;
  309.     values.foreground = w->cubes.foreground;
  310.     values.background = w->core.background_pixel;
  311.     XtReleaseGC(new, w->cubes.puzzleGC);
  312.     w->cubes.puzzleGC = XtGetGC(new, valueMask, &values);
  313.     redrawBricks = TRUE;
  314.   }
  315.   if (w->core.background_pixel != c->core.background_pixel) {
  316.     valueMask = GCForeground | GCBackground;
  317.     values.foreground = w->core.background_pixel;
  318.     values.background = w->cubes.foreground;
  319.     XtReleaseGC(new, w->cubes.inverseGC);
  320.     w->cubes.inverseGC = XtGetGC(new, valueMask, &values);
  321.     redrawBricks = TRUE;
  322.   }
  323.   if (w->cubes.brickColor != c->cubes.brickColor) {
  324.     valueMask = GCForeground | GCBackground;
  325.     values.foreground = w->cubes.brickColor;
  326.     values.background = w->core.background_pixel;
  327.     XtReleaseGC(new, w->cubes.brickGC);
  328.     w->cubes.brickGC = XtGetGC(new, valueMask, &values);
  329.     redrawBricks = TRUE;
  330.   }
  331.   if (w->cubes.borderColor != c->cubes.borderColor) {
  332.     valueMask = GCForeground | GCBackground;
  333.     values.foreground = w->cubes.borderColor;
  334.     values.background = w->core.background_pixel;
  335.     XtReleaseGC(new, w->cubes.borderGC);
  336.     w->cubes.borderGC = XtGetGC(new, valueMask, &values);
  337.     redrawBricks = TRUE;
  338.   }
  339.   if (w->cubes.sizeX != c->cubes.sizeX ||
  340.       w->cubes.sizeY != c->cubes.sizeY ||
  341.       w->cubes.sizeZ != c->cubes.sizeZ ||
  342.       w->cubes.base != c->cubes.base) {
  343.     ResetBricks(w);
  344.     ResizeCubes(w);
  345.     redraw = TRUE;
  346.   }
  347.   else if (w->cubes.offset.x != c->cubes.offset.x ||
  348.            w->cubes.offset.y != c->cubes.offset.y) {
  349.     ResizeCubes(w);
  350.     redraw = TRUE;
  351.   }
  352.   if (redrawBricks && !redraw && XtIsRealized(new) && new->core.visible) {
  353.     DrawFrame(c, c->cubes.inverseGC);
  354.     DrawAllBricks(c, c->cubes.inverseGC, c->cubes.inverseGC);
  355.     DrawFrame(w, w->cubes.puzzleGC);
  356.     DrawAllBricks(w, w->cubes.brickGC, w->cubes.borderGC);
  357.   }
  358.   return (redraw);
  359. }
  360.  
  361. static void QuitCubes(w, event, args, nArgs)
  362.   CubesWidget w;
  363.   XEvent *event;
  364.   char *args[];
  365.   int nArgs;
  366. {
  367.   XtCloseDisplay(XtDisplay(w));
  368.   exit(0);
  369. }
  370.  
  371. static void SelectCubes(w, event, args, nArgs)
  372.   CubesWidget w;
  373.   XEvent *event;
  374.   char *args[];
  375.   int nArgs;
  376. {
  377.   int pos, i, j, k;
  378.  
  379.   pos = PositionToBrick(w, event->xbutton.x, event->xbutton.y, &i, &j, &k);
  380.   if (pos >= 0) {
  381.     if (CheckSolved(w)) {
  382.       MoveNoBricks(w);
  383.       w->cubes.currentPosition = -1;
  384.       return;
  385.     }
  386.     w->cubes.currentPosition = pos;
  387.     w->cubes.currentRow[0] = i;
  388.     w->cubes.currentRow[1] = j;
  389.     w->cubes.currentRow[2] = k;
  390.     if (pos != w->cubes.spacePosition)
  391.       DrawBrick(w, w->cubes.borderGC, w->cubes.brickGC,
  392.         w->cubes.currentPosition, TRUE);
  393.     else
  394.       w->cubes.currentPosition = -1;
  395.   } else
  396.     w->cubes.currentPosition = -1;
  397. }
  398.  
  399. static void ReleaseCubes(w, event, args, nArgs)
  400.   CubesWidget w;
  401.   XEvent *event;
  402.   char *args[];
  403.   int nArgs;
  404. {
  405.   if (w->cubes.currentPosition == -1)
  406.     return;
  407.   DrawBrick(w, w->cubes.inverseGC, w->cubes.inverseGC,
  408.     w->cubes.currentPosition, TRUE);
  409.   DrawBrick(w, w->cubes.brickGC, w->cubes.borderGC,
  410.     w->cubes.currentPosition, FALSE);
  411.   SelectBricks(w, w->cubes.currentRow[0], w->cubes.currentRow[1],
  412.     w->cubes.currentRow[2]);
  413.   w->cubes.currentPosition = -1;
  414. }
  415.  
  416. static void RandomizeCubes(w, event, args, nArgs)
  417.   CubesWidget w;
  418.   XEvent *event;
  419.   char *args[];
  420.   int nArgs;
  421. {
  422.   RandomizeBricks(w);
  423. }
  424.  
  425. static void RandomizeCubesMaybe(w, event, args, nArgs)
  426.   CubesWidget w;
  427.   XEvent *event;
  428.   char *args[];
  429.   int nArgs;
  430. {
  431.   if (!w->cubes.started)
  432.     RandomizeBricks(w);
  433. }
  434.  
  435. static void GetCubes(w, event, args, nArgs)
  436.   CubesWidget w;
  437.   XEvent *event;
  438.   char *args[];
  439.   int nArgs;
  440. {
  441.   FILE *fp;
  442.   char c;
  443.   int i, sizeX, sizeY, sizeZ, moves;
  444.   cubesCallbackStruct cb;
  445.  
  446.   if ((fp = fopen(DATAFILE, "r")) == NULL)
  447.     (void) printf("Can not read %s for get.\n", DATAFILE);
  448.   else {
  449.     FlushMoves(w);
  450.     while ((c = getc(fp)) != EOF && c != SYMBOL);
  451.     (void) fscanf(fp, "%d", &sizeX);
  452.     if (sizeX >= MINCUBES) {
  453.       for (i = w->cubes.sizeX; i < sizeX; i++) {
  454.         cb.reason = CUBES_INC_X;
  455.         XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  456.       }
  457.       for (i = w->cubes.sizeX; i > sizeX; i--) {
  458.         cb.reason = CUBES_DEC_X;
  459.         XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  460.       }
  461.     } else
  462.       (void) printf("%s corrupted: sizeX %d should be between %d and MAXINT\n",
  463.          DATAFILE, sizeX, MINCUBES);
  464.     while ((c = getc(fp)) != EOF && c != SYMBOL);
  465.     (void) fscanf(fp, "%d", &sizeY);
  466.     if (sizeY >= MINCUBES) {
  467.       for (i = w->cubes.sizeY; i < sizeY; i++) {
  468.         cb.reason = CUBES_INC_Y;
  469.         XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  470.       }
  471.       for (i = w->cubes.sizeY; i > sizeY; i--) {
  472.         cb.reason = CUBES_DEC_Y;
  473.         XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  474.       }
  475.     } else
  476.       (void) printf("%s corrupted: sizeY %d should be between %d and MAXINT\n",
  477.          DATAFILE, sizeY, MINCUBES);
  478.     while ((c = getc(fp)) != EOF && c != SYMBOL);
  479.     (void) fscanf(fp, "%d", &sizeZ);
  480.     if (sizeZ >= MINCUBES) {
  481.       for (i = w->cubes.sizeZ; i < sizeZ; i++) {
  482.         cb.reason = CUBES_INC_Z;
  483.         XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  484.       }
  485.       for (i = w->cubes.sizeZ; i > sizeZ; i--) {
  486.         cb.reason = CUBES_DEC_Z;
  487.         XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  488.       }
  489.     } else
  490.       (void) printf("%s corrupted: sizeZ %d should be between %d and MAXINT\n",
  491.          DATAFILE, sizeZ, MINCUBES);
  492.     while ((c = getc(fp)) != EOF && c != SYMBOL);
  493.     (void) fscanf(fp, "%d", &moves);
  494.     ScanStartPosition(fp, w);
  495.     cb.reason = CUBES_RESTORE;
  496.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  497.     SetStartPosition(w);
  498.     ScanMoves(fp, w, moves);
  499.     (void) fclose(fp);
  500.     (void) printf("%s: sizeX %d, sizeY %d, sizeZ %d, moves %d.\n",
  501.       DATAFILE, sizeX, sizeY, sizeZ, moves);
  502.   }
  503. }
  504.  
  505. static void WriteCubes(w, event, args, nArgs)
  506.   CubesWidget w;
  507.   XEvent *event;
  508.   char *args[];
  509.   int nArgs;
  510. {
  511.   FILE *fp;
  512.  
  513.   if ((fp = fopen(DATAFILE, "w")) == NULL)
  514.     (void) printf("Can not write to %s.\n", DATAFILE);
  515.   else {
  516.     (void) fprintf(fp, "sizeX%c %d\n", SYMBOL, w->cubes.sizeX);
  517.     (void) fprintf(fp, "sizeY%c %d\n", SYMBOL, w->cubes.sizeY);
  518.     (void) fprintf(fp, "sizeZ%c %d\n", SYMBOL, w->cubes.sizeZ);
  519.     (void) fprintf(fp, "moves%c %d\n", SYMBOL, NumMoves());
  520.     PrintStartPosition(fp, w);
  521.     PrintMoves(fp);
  522.     (void) fclose(fp);
  523.     (void) printf("Saved to %s.\n", DATAFILE);
  524.   }
  525. }
  526.  
  527. static void UndoCubes(w, event, args, nArgs)
  528.   CubesWidget w;
  529.   XEvent *event;
  530.   char *args[];
  531.   int nArgs;
  532. {
  533.   if (MadeMoves()) {
  534.     int direction;
  535.  
  536.     GetMove(&direction);
  537.     direction = (direction < 4) ? (direction + 2) % 4 :
  538.       ((direction == IN) ?  OUT : IN);
  539.  
  540.     if (MoveBricksDir(w, direction)) {
  541.       cubesCallbackStruct cb;
  542.  
  543.       cb.reason = CUBES_UNDO;
  544.       XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  545.     }
  546.   }
  547. }
  548.  
  549. static void SolveCubes(w, event, args, nArgs)
  550.   CubesWidget w;
  551.   XEvent *event;
  552.   char *args[];
  553.   int nArgs;
  554. {
  555.   /* SolveBricks(w); */ /* Sorry, unimplemented */
  556. }
  557.  
  558. static void MoveCubesOut(w, event, args, nArgs)
  559.   CubesWidget w;
  560.   XEvent *event;
  561.   char *args[];
  562.   int nArgs;
  563. {
  564.   (void) MoveCubes(w, OUT, (int) (event->xkey.state & ControlMask));
  565. }
  566.  
  567. static void MoveCubesTop(w, event, args, nArgs)
  568.   CubesWidget w;
  569.   XEvent *event;
  570.   char *args[];
  571.   int nArgs;
  572. {
  573.   (void) MoveCubes(w, TOP, (int) (event->xkey.state & ControlMask));
  574. }
  575.  
  576. static void MoveCubesLeft(w, event, args, nArgs)
  577.   CubesWidget w;
  578.   XEvent *event;
  579.   char *args[];
  580.   int nArgs;
  581. {
  582.   (void) MoveCubes(w, LEFT, (int) (event->xkey.state & ControlMask));
  583. }
  584.  
  585. static void MoveCubesIn(w, event, args, nArgs)
  586.   CubesWidget w;
  587.   XEvent *event;
  588.   char *args[];
  589.   int nArgs;
  590. {
  591.   (void) MoveCubes(w, IN, (int) (event->xkey.state & ControlMask));
  592. }
  593.  
  594. static void MoveCubesRight(w, event, args, nArgs)
  595.   CubesWidget w;
  596.   XEvent *event;
  597.   char *args[];
  598.   int nArgs;
  599. {
  600.   (void) MoveCubes(w, RIGHT, (int) (event->xkey.state & ControlMask));
  601. }
  602.  
  603. static void MoveCubesBottom(w, event, args, nArgs)
  604.   CubesWidget w;
  605.   XEvent *event;
  606.   char *args[];
  607.   int nArgs;
  608. {
  609.   (void) MoveCubes(w, BOTTOM, (int) (event->xkey.state & ControlMask));
  610. }
  611.  
  612. static int MoveCubes(w, direction, control)
  613.   CubesWidget w;
  614.   int direction, control;
  615. {
  616.   cubesCallbackStruct cb;
  617.  
  618.   if (control) {
  619.     cb.reason = CUBES_IGNORE;
  620.     switch (direction) {
  621.       case TOP:
  622.         if (w->cubes.sizeY <= MINCUBES)
  623.           return FALSE;
  624.         cb.reason = CUBES_DEC_Y;
  625.         break;
  626.       case RIGHT:
  627.         cb.reason = CUBES_INC_X;
  628.         break;
  629.       case BOTTOM:
  630.         cb.reason = CUBES_INC_Y;
  631.         break;
  632.       case LEFT:
  633.         if (w->cubes.sizeX <= MINCUBES)
  634.           return FALSE;
  635.         cb.reason = CUBES_DEC_X;
  636.         break;
  637.       case IN:
  638.         if (w->cubes.sizeZ <= MINCUBES)
  639.           return FALSE;
  640.         cb.reason = CUBES_DEC_Z;
  641.         break;
  642.       case OUT:
  643.         cb.reason = CUBES_INC_Z;
  644.         break;
  645.       default:
  646.         (void) printf("MoveCubes: direction %d\n", direction);
  647.     }
  648.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  649.     return FALSE;
  650.   }
  651.   if (CheckSolved(w)) {
  652.     MoveNoBricks(w);
  653.     return FALSE;
  654.   }
  655.   if (!MoveCubesDir(w, direction)) {
  656.     cb.reason = CUBES_BLOCKED;
  657.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  658.     return FALSE;
  659.   }
  660.   if (CheckSolved(w)) {
  661.     cb.reason = CUBES_SOLVED;
  662.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  663.   }
  664.   return TRUE;
  665. }
  666.  
  667. int MoveCubesDir(w, direction)
  668.   CubesWidget w;
  669.   int direction;
  670. {
  671.   cubesCallbackStruct cb;
  672.  
  673.   if (MoveBricksDir(w, direction)) {
  674.     cb.reason = CUBES_MOVED;
  675.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  676.     PutMove(direction);
  677.     return TRUE;
  678.   }
  679.   return FALSE;
  680. }
  681.  
  682. static int PositionToBrick(w, x, y, i, j, k)
  683.   CubesWidget w;
  684.   int x, y;
  685.   int *i, *j, *k;
  686. {
  687.   if (w->cubes.vertical) {
  688.     *i = (x - w->cubes.delta.x / 2 -
  689.       w->cubes.puzzleOffset.x) / w->cubes.offset.x;
  690.     *j = ((y - w->cubes.delta.y / 2 -
  691.       w->cubes.puzzleOffset.y) % (w->cubes.sizeY * w->cubes.offset.y +
  692.       w->cubes.delta.y - 1)) / w->cubes.offset.y;
  693.     *k = (y - w->cubes.delta.y / 2 -
  694.       w->cubes.puzzleOffset.y) / (w->cubes.sizeY * w->cubes.offset.y +
  695.       w->cubes.delta.y - 1);
  696.   } else {
  697.     *i = ((x - w->cubes.delta.x / 2 -
  698.       w->cubes.puzzleOffset.x) % (w->cubes.sizeX * w->cubes.offset.x +
  699.       w->cubes.delta.x - 1)) / w->cubes.offset.x;
  700.     *j = (y - w->cubes.delta.y / 2 -
  701.       w->cubes.puzzleOffset.y) / w->cubes.offset.y;
  702.     *k = (x - w->cubes.delta.x / 2 -
  703.       w->cubes.puzzleOffset.x) / (w->cubes.sizeX * w->cubes.offset.x +
  704.       w->cubes.delta.x - 1);
  705.   }
  706.   if (*i >= 0 && *j >= 0 && *k >= 0 &&
  707.       *i < w->cubes.sizeX && *j < w->cubes.sizeY && *k < w->cubes.sizeZ)
  708.     return  (*i + w->cubes.sizeX * *j + w->cubes.sizeRect * *k);
  709.   else
  710.     return -1;
  711. }
  712.  
  713. static void SelectBricks(w, i, j, k)
  714.   CubesWidget w;
  715.   int i, j, k;
  716. {
  717.   cubesCallbackStruct cb;
  718.   int l, m, n;
  719.  
  720.   l = i + w->cubes.sizeX * j - w->cubes.spacePosition % w->cubes.sizeRect;
  721.   m = i + w->cubes.sizeX * j + w->cubes.sizeRect * k - w->cubes.spacePosition;
  722.   /* Order important if w->cubes.sizeX = 1 */
  723.   if (l % w->cubes.sizeX == 0 && k == Stack(w, w->cubes.spacePosition)) {
  724.     if (l < 0) {
  725.       for (n = 1; n <= -l / w->cubes.sizeX; n++) {
  726.         MoveBricks(w, w->cubes.spacePosition - w->cubes.sizeX);
  727.         cb.reason = CUBES_MOVED;
  728.         XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  729.         PutMove(BOTTOM);
  730.       }
  731.     } else if (l > 0) {
  732.       for (n = 1; n <= l / w->cubes.sizeX; n++) {
  733.         MoveBricks(w, w->cubes.spacePosition + w->cubes.sizeX);
  734.         cb.reason = CUBES_MOVED;
  735.         XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  736.         PutMove(TOP);
  737.       }
  738.     } else /* (l == 0) */ {
  739.       cb.reason = CUBES_SPACE;
  740.       XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  741.       return;
  742.     }
  743.   } else if (l / w->cubes.sizeX == 0 &&
  744.              j == Column(w, w->cubes.spacePosition) &&
  745.              k == Stack(w, w->cubes.spacePosition)) {
  746.     if (l < 0) {
  747.       for (n = 1; n <= -l % w->cubes.sizeX; n++) {
  748.         MoveBricks(w, w->cubes.spacePosition - 1);
  749.         cb.reason = CUBES_MOVED;
  750.         XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  751.         PutMove(RIGHT);
  752.       }
  753.     } else /* (l > 0) */ {
  754.       for (n = 1; n <= l % w->cubes.sizeX; n++) {
  755.         MoveBricks(w, w->cubes.spacePosition + 1);
  756.         cb.reason = CUBES_MOVED;
  757.         XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  758.         PutMove(LEFT);
  759.       }
  760.     }
  761.   } else if (m % w->cubes.sizeRect == 0) {
  762.     if (m < 0) {
  763.       for (n = 1; n <= -Stack(w, m); n++) {
  764.         MoveBricks(w, w->cubes.spacePosition - w->cubes.sizeRect);
  765.         cb.reason = CUBES_MOVED;
  766.         XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  767.         PutMove(IN);
  768.       }
  769.     } else /* (m > 0) */ {
  770.       for (n = 1; n <= Stack(w, m); n++) {
  771.         MoveBricks(w, w->cubes.spacePosition + w->cubes.sizeRect);
  772.         cb.reason = CUBES_MOVED;
  773.         XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  774.         PutMove(OUT);
  775.       }
  776.     }
  777.   } else {
  778.     cb.reason = CUBES_BLOCKED;
  779.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  780.     return;
  781.   }
  782.   if (CheckSolved(w)) {
  783.     cb.reason = CUBES_SOLVED;
  784.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  785.   }
  786. }
  787.  
  788. static void CheckBricks(w)
  789.   CubesWidget w;
  790. {
  791.   char buf[121];
  792.  
  793.   if (w->cubes.sizeX < MINCUBES) {
  794.     (void) sprintf(buf,
  795.              "Number of Cubes in X direction out of bounds, use %d..MAXINT",
  796.              MINCUBES);
  797.     XtWarning(buf);
  798.     w->cubes.sizeX = DEFAULTCUBES;
  799.   }
  800.   if (w->cubes.sizeY < MINCUBES) {
  801.     (void) sprintf(buf,
  802.              "Number of Cubes in Y direction out of bounds, use %d..MAXINT",
  803.              MINCUBES);
  804.     XtWarning(buf);
  805.     w->cubes.sizeY = DEFAULTCUBES;
  806.   }
  807.   if (w->cubes.sizeZ < MINCUBES) {
  808.     (void) sprintf(buf,
  809.              "Number of Cubes in Z direction out of bounds, use %d..MAXINT",
  810.              MINCUBES);
  811.     XtWarning(buf);
  812.     w->cubes.sizeZ = DEFAULTCUBES;
  813.   }
  814.   w->cubes.base = 10;
  815. }
  816.  
  817. static void ResetBricks(w)
  818.   CubesWidget w;
  819. {
  820.   int i;
  821.  
  822.   w->cubes.sizeRect = w->cubes.sizeX * w->cubes.sizeY; 
  823.   w->cubes.sizeBlock = w->cubes.sizeRect * w->cubes.sizeZ; 
  824.   if (w->cubes.brickOfPosition)
  825.     (void) free((void *) w->cubes.brickOfPosition);
  826.   if (!(w->cubes.brickOfPosition = (int *)
  827.         malloc(sizeof(int) * w->cubes.sizeBlock)))
  828.     XtError("Not enough memory, exiting.");
  829.   if (startPosition)
  830.     (void) free((void *) startPosition);
  831.   if (!(startPosition = (int *)
  832.         malloc(sizeof(int) * w->cubes.sizeBlock)))
  833.     XtError("Not enough memory, exiting.");
  834.   w->cubes.spacePosition = w->cubes.sizeBlock - 1;
  835.   w->cubes.brickOfPosition[w->cubes.sizeBlock - 1] = 0;
  836.   for (i = 1; i < w->cubes.sizeBlock; i++)
  837.     w->cubes.brickOfPosition[i - 1] = i;
  838.   FlushMoves(w);
  839.   w->cubes.currentPosition = -1;
  840.   w->cubes.started = FALSE;
  841. }
  842.  
  843. static void ResizeBricks(w)
  844.   CubesWidget w;
  845. {
  846.   w->cubes.digitOffset.x = 3;
  847.   w->cubes.digitOffset.y = 4;
  848. }
  849.  
  850. static void MoveNoBricks(w)
  851.   CubesWidget w;
  852. {
  853.   cubesCallbackStruct cb;
  854.  
  855.   cb.reason = CUBES_IGNORE;
  856.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  857. }
  858.  
  859. static int MoveBricksDir(w, direction)
  860.   CubesWidget w;
  861.   int direction;
  862. {
  863.   switch (direction) {
  864.     case TOP:
  865.       if (Column(w, w->cubes.spacePosition) < w->cubes.sizeY - 1) {
  866.         MoveBricks(w, w->cubes.spacePosition + w->cubes.sizeX);
  867.         return TRUE;
  868.       }
  869.       break;
  870.     case RIGHT:
  871.       if (Row(w, w->cubes.spacePosition) > 0) {
  872.         MoveBricks(w, w->cubes.spacePosition - 1);
  873.         return TRUE;
  874.       }
  875.       break;
  876.     case BOTTOM:
  877.       if (Column(w, w->cubes.spacePosition) > 0) {
  878.         MoveBricks(w, w->cubes.spacePosition - w->cubes.sizeX);
  879.         return TRUE;
  880.       }
  881.       break;
  882.     case LEFT:
  883.       if (Row(w, w->cubes.spacePosition) < w->cubes.sizeX - 1) {
  884.         MoveBricks(w, w->cubes.spacePosition + 1);
  885.         return TRUE;
  886.       }
  887.       break;
  888.     case IN:
  889.       if (Stack(w, w->cubes.spacePosition) > 0) {
  890.         MoveBricks(w, w->cubes.spacePosition - w->cubes.sizeRect);
  891.         return TRUE;
  892.       }
  893.       break;
  894.     case OUT:
  895.       if (Stack(w, w->cubes.spacePosition) < w->cubes.sizeZ - 1) {
  896.         MoveBricks(w, w->cubes.spacePosition + w->cubes.sizeRect);
  897.         return TRUE;
  898.       }
  899.       break;
  900.     default:
  901.       (void) printf("MoveBricksDir: direction %d\n", direction);
  902.   }
  903.   return FALSE;
  904. }
  905.  
  906. static void RandomizeBricks(w)
  907.   CubesWidget w;
  908. {
  909.   cubesCallbackStruct cb;
  910.  
  911.   /* First interchange bricks an even number of times */
  912.   if (w->cubes.sizeX > 1 && w->cubes.sizeY > 1 && w->cubes.sizeZ > 1 &&
  913.       w->cubes.sizeBlock > 4) {
  914.     int pos, count = 0;
  915.  
  916.     for (pos = 0; pos < w->cubes.sizeBlock; pos++) {
  917.        int randomPos = pos;
  918.  
  919.        while (randomPos == pos)
  920.          randomPos = NRAND(w->cubes.sizeBlock);
  921.        count += ExchangeBricks(w, pos, randomPos);
  922.     }
  923.     if (count % 2)
  924.       if (!ExchangeBricks(w, 0, 1))
  925.         if (!ExchangeBricks(w, w->cubes.sizeBlock - 2, w->cubes.sizeBlock - 1))
  926.           (void) printf("RandomizeBricks: should not get here\n");
  927.     DrawAllBricks(w, w->cubes.brickGC, w->cubes.borderGC);
  928.   }
  929.   /* Now move the space around randomly */
  930.   if (w->cubes.sizeX > 1 || w->cubes.sizeY > 1 || w->cubes.sizeZ > 1) {
  931.     int big = w->cubes.sizeBlock + NRAND(2);
  932.     int lastDirection = 0;
  933.     int randomDirection;
  934.  
  935.     cb.reason = CUBES_RESET;
  936.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  937.  
  938. #ifdef DEBUG
  939.     big = 3;
  940. #endif
  941.  
  942.     if (big > 1000)
  943.       big = 1000;
  944.     while (big--) {
  945.       randomDirection = NRAND(COORD);
  946.  
  947. #ifdef DEBUG
  948.       sleep(1);
  949. #endif
  950.  
  951.       if ((randomDirection + COORD / 2) % COORD != lastDirection ||
  952.           (w->cubes.sizeX == 1 && w->cubes.sizeY == 1) ||
  953.           (w->cubes.sizeY == 1 && w->cubes.sizeZ == 1) ||
  954.           (w->cubes.sizeZ == 1 && w->cubes.sizeX == 1)) {
  955.         if (MoveCubesDir(w, randomDirection))
  956.           lastDirection = randomDirection;
  957.         else
  958.           big++;
  959.       }
  960.     }
  961.     FlushMoves(w);
  962.     cb.reason = CUBES_RANDOMIZE;
  963.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  964.   }
  965.   if (CheckSolved(w)) {
  966.     cb.reason = CUBES_SOLVED;
  967.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  968.   }
  969. }
  970.  
  971. static void MoveBricks(w, from)
  972.   CubesWidget w;
  973.   int from;
  974. {
  975.   int tempBrick;
  976.  
  977.   tempBrick = w->cubes.brickOfPosition[from];
  978.   w->cubes.brickOfPosition[from] =
  979.     w->cubes.brickOfPosition[w->cubes.spacePosition];
  980.   w->cubes.brickOfPosition[w->cubes.spacePosition] = tempBrick;
  981.   DrawBrick(w, w->cubes.brickGC, w->cubes.borderGC, w->cubes.spacePosition,
  982.     FALSE);
  983.   w->cubes.spacePosition = from;
  984.   DrawBrick(w, w->cubes.inverseGC, w->cubes.inverseGC, w->cubes.spacePosition,
  985.     FALSE);
  986. }
  987.  
  988. static int ExchangeBricks(w, pos1, pos2)
  989.   CubesWidget w;
  990.   int pos1, pos2;
  991. {
  992.   int tempBrick;
  993.  
  994.   if (w->cubes.brickOfPosition[pos1] <= 0)
  995.     return FALSE;
  996.   else if (w->cubes.brickOfPosition[pos2] <= 0)
  997.     return FALSE;
  998.   tempBrick = w->cubes.brickOfPosition[pos1];
  999.   w->cubes.brickOfPosition[pos1] = w->cubes.brickOfPosition[pos2];
  1000.   w->cubes.brickOfPosition[pos2] = tempBrick;
  1001.   return TRUE;
  1002. }
  1003.  
  1004. static void DrawFrame(w, gc)
  1005.   CubesWidget w;
  1006.   GC gc;
  1007. {
  1008.   int sumX, sumY, sumZ, offsetX, offsetY, dz, k;
  1009.  
  1010.   sumX = w->cubes.sizeX * w->cubes.offset.x + w->cubes.delta.x / 2 + 1;
  1011.   sumY = w->cubes.sizeY * w->cubes.offset.y + w->cubes.delta.y / 2 + 1;
  1012.   offsetX = w->cubes.puzzleOffset.x;
  1013.   offsetY = w->cubes.puzzleOffset.y;
  1014.   if (w->cubes.vertical) {
  1015.     sumZ = offsetY;
  1016.     dz = sumY;
  1017.   } else {
  1018.     sumZ = offsetX;
  1019.     dz = sumX;
  1020.   }
  1021.   for (k = 0; k < w->cubes.sizeZ; k++)
  1022.   {
  1023.     if (w->cubes.vertical) {
  1024.       XFillRectangle(XtDisplay(w), XtWindow(w), gc, 
  1025.         offsetX, sumZ, 1, sumY);
  1026.       XFillRectangle(XtDisplay(w), XtWindow(w), gc,
  1027.         offsetX, sumZ, sumX, 1);
  1028.       XFillRectangle(XtDisplay(w), XtWindow(w), gc,
  1029.         sumX + offsetX, sumZ, 1, sumY + 1);
  1030.       XFillRectangle(XtDisplay(w), XtWindow(w), gc,
  1031.         offsetX, sumY + sumZ, sumX + 1, 1);
  1032.     } else {
  1033.       XFillRectangle(XtDisplay(w), XtWindow(w), gc, 
  1034.         sumZ, offsetY, 1, sumY);
  1035.       XFillRectangle(XtDisplay(w), XtWindow(w), gc,
  1036.         sumZ, offsetY, sumX, 1);
  1037.       XFillRectangle(XtDisplay(w), XtWindow(w), gc,
  1038.         sumX + sumZ, offsetY, 1, sumY + 1);
  1039.       XFillRectangle(XtDisplay(w), XtWindow(w), gc,
  1040.         sumZ, sumY + offsetY, sumX + 1, 1);
  1041.     }
  1042.     sumZ += dz;
  1043.   }
  1044. }   
  1045.  
  1046. void DrawAllBricks(w, brickGC, borderGC)
  1047.   CubesWidget w;
  1048.   GC brickGC, borderGC;
  1049. {
  1050.   int k;
  1051.  
  1052.   for (k = 0; k < w->cubes.sizeBlock; k++)
  1053.     if (w->cubes.brickOfPosition[k] <= 0)
  1054.       DrawBrick(w, w->cubes.inverseGC, w->cubes.inverseGC, k, FALSE);
  1055.     else
  1056.       DrawBrick(w, brickGC, borderGC, k, FALSE);
  1057. }
  1058.  
  1059. static void DrawBrick(w, brickGC, borderGC, pos, offset)
  1060.   CubesWidget w;
  1061.   GC brickGC, borderGC;
  1062.   int pos, offset;
  1063. {
  1064.   int dx, dy, dz;
  1065.  
  1066.   if (w->cubes.vertical) {
  1067.     dx = Row(w, pos) * w->cubes.offset.x + w->cubes.delta.x +
  1068.       w->cubes.puzzleOffset.x + offset;
  1069.     dy = Column(w, pos) * w->cubes.offset.y + w->cubes.delta.y +
  1070.       w->cubes.puzzleOffset.y + offset;
  1071.     dz = Stack(w, pos) * (w->cubes.sizeY * w->cubes.offset.y +
  1072.       w->cubes.delta.y - 1);
  1073.     dy += dz;
  1074.   } else {
  1075.     dx = Row(w, pos) * w->cubes.offset.x + w->cubes.delta.x +
  1076.       w->cubes.puzzleOffset.x + offset;
  1077.     dy = Column(w, pos) * w->cubes.offset.y + w->cubes.delta.y +
  1078.       w->cubes.puzzleOffset.y + offset;
  1079.     dz = Stack(w, pos) * (w->cubes.sizeX * w->cubes.offset.x +
  1080.       w->cubes.delta.x - 1);
  1081.     dx += dz;
  1082.   }
  1083.   XFillRectangle(XtDisplay(w), XtWindow(w), brickGC, dx, dy,
  1084.     w->cubes.brickSize.x, w->cubes.brickSize.y);
  1085.   XDrawRectangle(XtDisplay(w), XtWindow(w), borderGC, dx, dy,
  1086.     w->cubes.brickSize.x, w->cubes.brickSize.y);
  1087.   if (brickGC != w->cubes.inverseGC) {
  1088.     int i = 0, offsetX = 0, brick = w->cubes.brickOfPosition[pos];
  1089.     char buf[5];
  1090.  
  1091.     (void) sprintf(buf, "%d", brick);
  1092.     while (brick >= 1) {
  1093.       brick /= w->cubes.base;
  1094.       offsetX += w->cubes.digitOffset.x;
  1095.       i++;
  1096.     }
  1097.     XDrawString(XtDisplay(w), XtWindow(w), w->cubes.inverseGC,
  1098.       dx + w->cubes.brickSize.x / 2 - offsetX,
  1099.       dy + w->cubes.brickSize.y / 2 + w->cubes.digitOffset.y, buf, i);
  1100.   }
  1101. }
  1102.  
  1103. static int Row(w, pos)
  1104.   CubesWidget w;
  1105.   int pos;
  1106. {
  1107.   return ((pos % w->cubes.sizeRect) % w->cubes.sizeX);
  1108. }
  1109.  
  1110. static int Column(w, pos)
  1111.   CubesWidget w;
  1112.   int pos;
  1113. {
  1114.   return ((pos % w->cubes.sizeRect) / w->cubes.sizeX);
  1115. }
  1116.  
  1117. static int Stack(w, pos)
  1118.   CubesWidget w;
  1119.   int pos;
  1120. {
  1121.   return (pos / w->cubes.sizeRect);
  1122. }
  1123.  
  1124. Boolean CheckSolved(w)
  1125.   CubesWidget w;
  1126. {
  1127.   int i;
  1128.  
  1129.   for (i = 1; i < w->cubes.sizeBlock; i++)
  1130.     if (w->cubes.brickOfPosition[i - 1] != i)
  1131.       return FALSE;
  1132.   return TRUE;
  1133. }
  1134.